package BLL;

import java.util.*;

import DTO.*;
import DAL.*;

/**
 * Classe responsavel pela geração dos elementos de um jogo (JogoDTO)
 *
 * @author (R. Soares)
 * @version (1.0 - 25.05.2010)
 */
public class GeradorJogo
{
    // Variáveis de Instancia ------------------------------------------ *
   private ConfiguracaoDTO _configuracaoDTO;
   private final int _faseInicial = 1;
   private final int _escoreInicial = 0;
   private final int _chancesJogoInicial = 3;
   private final int _quantidadeInicialMeteoros = 3;
   private final int _resistenciaInicialMeteoros = 1;
   private final String _nivelPartidaInicial = "Facil";
    /**
     * Construtor da Classe GeradorJogo
     */
    public GeradorJogo()
    {
        _configuracaoDTO = new ConfiguracaoDAL().obterConfiguracao();
    }

    // Método ------------------------------------------------------- *
    /**
     * Método que gera um novo Jogo com o identificador único informado. O novo
     * jogo tera Fase = 1, Escore = 0, Chances de Jogo = 3 e três meteoros com
     * resistência igual a 1.
     *
     * @return   JogoDTO : novo jogo gerado
     */
    public JogoDTO gerarNovoJogo(String identificador, String nomePartida)
    {
        int[] listaResistencias = new int[ _quantidadeInicialMeteoros ];

        for(int i = 0; i < _quantidadeInicialMeteoros; i++)
        {
            listaResistencias[i] = _resistenciaInicialMeteoros;
        }

        JogoDTO jogo = new JogoDTO( identificador, _faseInicial,
                           _escoreInicial, _chancesJogoInicial,
                           gerarMeteoros(_quantidadeInicialMeteoros, listaResistencias), _nivelPartidaInicial, nomePartida);

        jogo.setPlaneta( gerarPlaneta() );
        jogo.setSatelite( gerarSatelite() );
        jogo.setMissil( gerarMissil() );

        return jogo;
    }

    /**
     * Método que gera um novo que está salvo. Recebe como parametro um objeto jogo
     *
     * @return   JogoDTO : jogo gerado
     */
    public JogoDTO gerarJogoSalvo(JogoDTO jogo)
    {
        ListaMeteoros listaMeteoros= jogo.getListaMeteoros();
        int[] chaves = listaMeteoros.retornaChaveMeteoros();
        int[] listaResistencias = new int[ listaMeteoros.getQuantidadeMeteoros() ];

        for(int i = 0; i < listaMeteoros.getQuantidadeMeteoros(); i++)
        {
            listaResistencias[i] = listaMeteoros.retornaMeteoro( chaves[i] ).
                                                                            getPontosResistencia();
        }


        listaMeteoros = gerarMeteoros(listaMeteoros.getQuantidadeMeteoros(),
                                                                                                     listaResistencias );
        jogo.setListaMeteoros( listaMeteoros );
        jogo.setPlaneta( gerarPlaneta() );
        jogo.setSatelite( gerarSatelite() );
        jogo.setMissil( gerarMissil() );

        return jogo;
    }

    /**
     * Método que gera um novo elemento satélite
     *
     * @return   ElementoDTO : Novo satélite gerado.
     */
    private SateliteDTO gerarSatelite()
    {
        //Determina a que distancia o satélite ficará da área de jogo.
        double distanciaCentro = _configuracaoDTO.getDiametroTerra() / 2  +
                                                  _configuracaoDTO.getDiametroSatelite() / 1.5;

         // Determina as coordenada da posição inicial do Satélite. A coordenada Y
         // será  subtraída da distancia do centro para que posicione acima do planeta
         double posicaoX = _configuracaoDTO.getLarguraTela() / 2;
         double posicaoY = ( _configuracaoDTO.getAlturaTela() / 2 ) - distanciaCentro;

         // Cria um novo satélite, com angulo inicial de 90.
         SateliteDTO satelite = new SateliteDTO( distanciaCentro, 90,
                                                    _configuracaoDTO.getLarguraTela() / 2,
                                                    _configuracaoDTO.getAlturaTela() / 2 );

          // O elemento satélite recebe o valor de diametro, velocidade e localização
         satelite.setDiametro( _configuracaoDTO.getDiametroSatelite() );
         satelite.setVelocidade( _configuracaoDTO.getVelocidadeSatelite() );
         satelite.setLocalizacaoAtual( new Ponto( posicaoX, posicaoY) );

         return satelite;
    }

    /**
     * Método que gera um novo elemento planeta.
     *
     * @return  ElementoDTO : novo planeta gerado.
     */
    private ElementoDTO gerarPlaneta()
    {
        ElementoDTO planeta = new ElementoDTO();

        planeta.setDiametro(_configuracaoDTO.getDiametroTerra() );

        // Localização do planeta recebe as coordendas do centro da área de jogo
        planeta.setLocalizacaoAtual( new Ponto(
                                                             _configuracaoDTO.getLarguraTela() / 2,
                                                              _configuracaoDTO.getAlturaTela() / 2 ) );
         return planeta;
    }

    /**
     * Método que gera um elemento missil. O elemento gerado mantem as configurações
     * para a geração de mísseis durante a execução do jogo.
     *
     * @return  ElementoDTO : missel gerado.
     */
    private ElementoDTO gerarMissil()
    {
        ElementoDTO missil = new ElementoDTO();

        // Elemento missíl recebe valor de diametro, velocidade e massa
        missil.setDiametro( _configuracaoDTO.getDiametroMissil() );
        missil.setVelocidade( _configuracaoDTO.getVelocidadeMissil() );
        missil.setMassa(_configuracaoDTO.getMassaMissil() );

        return missil;
    }

    /**
     * Método que gera lista com objetos Meteoro. Recebe como parametros a
     * quantidade de meteoros a serem gerados e a resistência dos meteoros.
     *
     * @param  int - numeroMeteoros : Quantidade de meteoros
     * @param  int - resistencia : Resistencia dos meteoros
     * @return   ListaMeteoros : Lista dos meteoros gerados.
     */
    public ListaMeteoros gerarMeteoros(int numeroMeteoros, int[] resistencia)
    {
        ListaMeteoros listaMeteoros = new ListaMeteoros();

        ArrayList listaMeteorosVerificar = new ArrayList();
        Iterator it = listaMeteorosVerificar.iterator();
        boolean existe = true;

        MeteoroDTO meteoro = null;

        for (int i = 0; i < numeroMeteoros; i++ )
        {
            while(existe)
             {
                existe = false;
                it = listaMeteorosVerificar.iterator();

                // Gera um novo meteoro com a resistencia informada
                meteoro = new  MeteoroDTO( i, resistencia[i]);

                // Meteoro gerado recebe diametro, velocidade e massa
                meteoro.setDiametro( _configuracaoDTO.getDiametroMeteoro() );
                meteoro.setVelocidade(_configuracaoDTO.getVelocidadeMeteoro() );
                meteoro.setMassa(_configuracaoDTO.getMassaMeteoro() );

                // Gerada e incluída a localização atual do meteoro
                meteoro.setLocalizacaoAtual( gerarOrigemMeteoro(_configuracaoDTO.getDiametroMeteoro() ) );

                // Meteoro recebe como ponto de destino o centro da tela (direção do planeta)
                meteoro.setDestino( new Ponto( _configuracaoDTO.getLarguraTela() / 2, _configuracaoDTO.getAlturaTela() / 2 ));

                /* Determina os componentes iniciais de velocidade: Para  os movimentos
                 * iniciais (antes de redirecionamento) é necessário determinar os compontes
                 * de velocidade.
                 */
                 meteoro = ( (MeteoroDTO) new ElementoJogo().
                                                                   determinarMovimentoInicial(meteoro) );

                 // Inicializa o ponto de destino do primeiro movimenro do meteoro para
                 // empregando as componente de velocidade determinadas.
                  meteoro.setDestino(new Ponto (
                                    meteoro.getLocalizacaoAtual().getCoordenadaX() +
                                    meteoro.getPxVelocidade(),
                                    meteoro.getLocalizacaoAtual().getCoordenadaY() +
                                    meteoro.getPyVelocidade() ) );

                  while( it.hasNext() && !existe)
                   {

                       if ( new ElementoJogo().detectarColisaoElementos(
                                                                       (ElementoDTO) it.next(), meteoro) )
                        existe = true;
                    }
            }

            listaMeteorosVerificar.add(meteoro);

            listaMeteoros.setMeteoro( meteoro );

             existe = true;
        }

        return listaMeteoros;
    }

    /**
     * Método que define posição de origem do meteoro de forma aleatória.
     *
     * @param  int - diametro : Diametro dos meteoros
     * @return  Ponto - origemMeteoro : Posição de origem do meteoro;
     */
    private Ponto gerarOrigemMeteoro(int diametro)
    {
        Ponto origemMeteoro = null;
        Random geradorNum = new Random();

        int larguraTela = _configuracaoDTO.getLarguraTela();
        int alturaTela   = _configuracaoDTO.getAlturaTela();
        int lado = 0;


          // Encontra número que define de qual lado o meteoro deve aparecer
          // 0 = acima; 1 = abaixo; 2 = esquerda; 3 = direita
          lado = geradorNum.nextInt(4);

          // Meteoro posicionado na área superior da tela
          if (lado == 0)
          {
                 // Coordenada Y = 0 e X = aleatório com máximo largura da tela.
                 origemMeteoro = new Ponto( geradorNum.nextInt(larguraTela), diametro / 2 );
           }

           // Meteoro posicionado na área inferior da tela
           if (lado == 1)
           {
                // Coordenada Y = altura da tela e X = aleatório com máximo largura da tela.
                origemMeteoro = new Ponto( geradorNum.nextInt(larguraTela),
                                                                                           alturaTela - diametro / 2);
            }

            // Meteoro posicionado na área esquerda da tela
            if (lado == 2)
            {
                  // Coordenada X = 0 e Y = aleatório com máximo altura da tela.
                  origemMeteoro = new Ponto( diametro / 2, geradorNum.nextInt(alturaTela) );
             }

             // Meteoro posicionado na área direita da tela
             if (lado == 3)
             {
                // Coordenada X = largura da tela e Y = aleatório com máximo altura da tela.
                origemMeteoro = new Ponto( larguraTela - diametro / 2,
                                                                          geradorNum.nextInt(alturaTela) );
              }

            return origemMeteoro;
    }
}
